package nl.liacs.swi.tower;

import java.awt.Color;
import java.util.List;
import java.util.Random;

/**
 * Tower class.
 * 
 * Contains the AI of a single tower.
 *
 * The AI (tower placing) is either
 *  - completely random (i.e. the tower placing is just rolling a dice)
 *  - based on a modified Ant Colony Optimization algorithm.
 */

public class Tower {
	
	float alpha_value = 0.8f;
	
	int firePower = 10;
	int range = 40;
	protected int RELOAD_TIME = 50;
	
	// default life is 10
	public int life = 10;
	public int totalLife = 10;

	protected int x;
	protected int y;

	private int map[][];
	private double pheromones[][];

	private boolean isShooting = false;
	private boolean isHitting = false;
	private boolean isDead = false;
	protected int tick = 0;
	private int pheromone = 5;

	private double kills = 0;
	private int hits = 0;
	private int threshold = 2;

	public void init() {
		// Make an internal copy of the world map
		map = Map.getSingletonObject().getMapCopy();

		pheromones = Map.getSingletonObject().pheromones;

		//newPosition();
		
		// pheromone is placed after each iteration
		//sprayPheromon(this.x, this.y);

		this.x *= 40;
		this.y *= 40;
	}
	
	public Tower(float alpha){
		init();
		this.alpha_value = alpha;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}
	
	public boolean isShooting() {
		return this.isShooting;
	}
	
	public boolean isHitting() {
		return this.isHitting;
	}

	public double getKills() {
		return kills;
	}

	public void setKills(double kills) {
		this.kills = kills;
	}
	
	public void clearKills()
	{
		this.kills = 0;
	}
	
	public void incKill() {
		this.kills++;
	}
	
	protected void sprayPheromon(int x, int y) {
		this.pheromones[y][x] = this.pheromone;
	}

	public boolean isDead() {
		return isDead;
	}

	public void setDead(boolean isDead) {
		this.isDead = isDead;
	}

	public void update(List<Ant> ants,List<Tower> towers) {
		if(this.isDead)
			return;
		this.isHitting = false;
		tick++;
		if (tick == RELOAD_TIME) {
			this.isShooting = true;
			this.shootAnts(ants);
			
		}
		if (tick > RELOAD_TIME) {
			this.isShooting = false;
			tick = 0;
		}
	}

	public void shootAnts(List<Ant> ants) {
		for (Ant ant : ants) {
			if (!ant.isDead() && this.canHit(ant)) {
				ant.getsShot(firePower);
				this.isHitting = true;
				this.hits++;
				if(ant.isDead()){
					this.incKill();
				}
				break;
			}
		}
	}
	
	public int getHits(){
		return this.hits;
	}

	public void setHits(int hits){
		this.hits = hits;
	}
	
	public boolean canHit(Ant ant) {
		if ((ant.getX() > this.x - this.range) && (ant.getX() < this.x + this.range) && (ant.getY() < this.y + this.range)
				&& (ant.getY() < this.y + this.range)) {
			return true;
		}
		return false;
	}
	
	/**
	 * this method gets called from the ant if he bits a tower
	 */
	public void getsShot(int firePower){
		life = life - firePower;
		if(life <= 0){
			this.setDead(true);
		}
	}
	
	/**
	 * this method gets called from the ant if he bits a tower
	 */
	public void heal(int healPower){
		if(!this.isDead && this.life < this.totalLife){
			this.life += healPower;
		}
	}

	public Color getColor() {
		return Color.BLACK;
	}
	
	public void newPosition(int mode) {
		
		if(mode==3)
			newPositionBasedOnACO();
		if(mode==2)
			newPositionPlainRandom();
		/*
		 * Use this method if you want plain random positions.
		 * i.e. do not use a swarm based algorithm.
		 *  no pheromones, heuristic information etc.. just roll a dice
		 *
		 * this method can be used to compare with an ACO based method.
		 */
		//newPositionPlainRandom();
		
	}
	
	/*
	 *  Determine a new position based on the Probabilsitic transistion rule
	 *  
	 *	That is, it's random but biased by the pheromone level;
	 */
	
	public void newPositionBasedOnACO()
	{
		int tx = 0;
		int ty = 0;
		float beta_value = 1;
		
		int to = 0;
		int N = Map.WIDTH*Map.HEIGHT;
		
		double d = 0.0;
	    for(to=0; to < N; to++){ 
		      d += Math.pow(Map.pheromones[ty][tx], (float)alpha_value);
	 	}
		
		while (true)
		{
			
			if ((this.map[ty][tx] != 1) && (Map.getSingletonObject().map[ty][tx] != 0xFF) && (Map.getSingletonObject().map[ty][tx] != 2))
			{
				// Transistion probability rule
				double p = Math.pow(Map.pheromones[ty][tx], (float)alpha_value) / d;
				
				Random r = new Random();
				double rand = r.nextDouble();
				if( rand <= p ) break; // roll dice and see if we choose the place
				//System.out.println(rand + " < " + p + "? ");
			}
			
			tx++;
			if (tx >= Map.WIDTH)
			{
				tx = 0;
				ty++;
			}
			if (ty >= Map.HEIGHT)
			{
				ty = 0;
			}
		}
		
		// We chose a node to place our tower, now place it there
		this.x = tx * 40;
		this.y = ty * 40;
		Map.getSingletonObject().map[ty][tx] = 0xFF;	// mark placae as taken for this round
	}
	
	/*
	 * New position plain random.
	 * Use this when you don't want use Swarm Optimization.
	 */
	public void newPositionPlainRandom()
	{
		Random randomGenerator = new Random();
		this.x = randomGenerator.nextInt(Map.WIDTH-1);
		this.y = randomGenerator.nextInt(Map.HEIGHT-1);
		//System.out.println("TOWER: y:" + y + " x:" + x);
		if(this.map[y][x] > 0)
			newPositionPlainRandom();
		else
		{
			this.x *= 40;
			this.y *= 40;
		}
	}
	

}
